/**
 * 节流函数，限制函数在指定时间间隔内只能执行一次
 * @template T - 被包装函数的类型
 * @param {T} fn - 需要节流的原函数
 * @param {number} delay - 节流时间间隔（毫秒）
 * @returns {(...args: Parameters<T>) => void} - 包装后的节流函数
 * @example
 * const throttledScrollHandler = throttle(updatePosition, 100);
 * window.addEventListener('scroll', throttledScrollHandler);
 */
export function throttle<T extends (...args: any[]) => any>(
  fn: T,
  delay: number,
): (...args: Parameters<T>) => void {
  let lastExec = 0
  let timeoutId: ReturnType<typeof setTimeout> | null = null

  return (...args: Parameters<T>) => {
    const now = Date.now()
    const timeSinceLastExec = now - lastExec

    if (timeSinceLastExec >= delay) {
      fn(...args)
      lastExec = now
    } else {
      if (timeoutId) clearTimeout(timeoutId)
      timeoutId = setTimeout(() => {
        fn(...args)
        lastExec = Date.now()
      }, delay - timeSinceLastExec)
    }
  }
}

/**
 * 防抖函数，延迟执行直到停止调用指定时间后
 * @template T - 被包装函数的类型
 * @param {T} fn - 需要防抖的原函数
 * @param {number} delay - 防抖延迟时间（毫秒）
 * @returns {(...args: Parameters<T>) => void & { cancel: () => void }} - 包装后的防抖函数（含取消方法）
 * @example
 * const debouncedSearch = debounce(fetchResults, 300);
 * searchInput.addEventListener('input', debouncedSearch);
 * // 取消未执行的调用
 * debouncedSearch.cancel();
 */
import type { Cancellable } from '../types'

export function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number,
): (...args: Parameters<T>) => void & Cancellable {
  let timeoutId: ReturnType<typeof setTimeout> | null = null

  const debounced = (...args: Parameters<T>) => {
    if (timeoutId) clearTimeout(timeoutId)
    timeoutId = setTimeout(() => fn(...args), delay)
  }

  debounced.cancel = () => {
    if (timeoutId) {
      clearTimeout(timeoutId)
      timeoutId = null
    }
  }

// 根据提示，先将表达式转换为 unknown 类型，再转换为目标类型
return debounced as unknown as (...args: Parameters<T>) => void & Cancellable
}
